package com.adams.access.db.dao.hibernate;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.util.Assert;

import com.adams.access.db.dao.GenericDao;
import com.adams.utils.ReflectionUtils;

public class HibernateGenericDao<T, PK extends Serializable> implements
		GenericDao<T, PK>
{

	protected Logger logger = LoggerFactory.getLogger(getClass());

	protected SessionFactory sessionFactory;

	protected Class<T> entityClass;

	public HibernateGenericDao()
	{
		this.entityClass = ReflectionUtils.getSuperClassGenricType(getClass());
	}

	public HibernateGenericDao(final SessionFactory sessionFactory,
			final Class<T> entityClass)
	{
		this.sessionFactory = sessionFactory;
		this.entityClass = entityClass;
	}

	public SessionFactory getSessionFactory()
	{
		return sessionFactory;
	}

	@Autowired
	public void setSessionFactory(
			final @Qualifier("sessionFactory") SessionFactory sessionFactory)
	{
		this.sessionFactory = sessionFactory;
	}

	public Session getSession()
	{

		return sessionFactory.getCurrentSession();
	}

	public void delete(T entity)
	{
		// TODO Auto-generated method stub
		Assert.notNull(entity, "entity不能为空");
		getSession().delete(entity);
		logger.debug("delete entity: {}", entity);
	}

	@SuppressWarnings("unchecked")
	public <X> List<X> query(String hql, Object... values)
	{
		// TODO Auto-generated method stub
		return createQuery(hql, values).list();
	}

	@SuppressWarnings("unchecked")
	public <X> List<X> query(String hql, Map<String, Object> values)
	{
		// TODO Auto-generated method stub
		return createQuery(hql, values).list();
	}

	@SuppressWarnings("unchecked")
	public <X> X findUnique(String hql, Object... values)
	{
		// TODO Auto-generated method stub
		return (X) createQuery(hql, values).uniqueResult();
	}

	@SuppressWarnings("unchecked")
	public <X> X findUnique(String hql, Map<String, Object> values)
	{
		// TODO Auto-generated method stub
		return (X) createQuery(hql, values).uniqueResult();
	}

	@SuppressWarnings("unchecked")
	public T findUnique(final Criterion... criterions)
	{
		return (T) createCriteria(criterions).uniqueResult();
	}

	@SuppressWarnings("unchecked")
	public T get(Serializable id)
	{
		// TODO Auto-generated method stub

		Assert.notNull(id, "id不能为空");
		return (T) getSession().get(entityClass, id);
	}

	public void save(T entity)
	{
		// TODO Auto-generated method stub
		Assert.notNull(entity, "entity不能为空");
		getSession().save(entity);
		logger.debug("save entity: {}", entity);
	}

	public void saveOrUpdate(T entity)
	{
		// TODO Auto-generated method stub
		Assert.notNull(entity, "entity不能为空");
		getSession().saveOrUpdate(entity);
		logger.debug("save entity: {}", entity);
	}

	public void update(T entity)
	{
		// TODO Auto-generated method stub
		Assert.notNull(entity, "entity不能为空");
		getSession().update(entity);
		logger.debug("save entity: {}", entity);

	}

	public Query createQuery(String queryString, Map<String, Object> values)
	{
		// TODO Auto-generated method stub
		Assert.hasText(queryString, "queryString不能为空");
		Query query = getSession().createQuery(queryString);
		query.setCacheable(true);
		;
		if (values != null)
		{
			query.setProperties(values);
		}

		return query;
	}

	public Query createQuery(String queryString, Object... values)
	{
		// TODO Auto-generated method stub
		Assert.hasText(queryString, "queryString不能为空");
		Query query = getSession().createQuery(queryString);
		query.setCacheable(true);
		;
		if (values != null)
		{
			for (int i = 0; i < values.length; i++)
			{
				if (values[i] != null
						&& StringUtils.isNotEmpty(values[i].toString()))
					query.setParameter(i, values[i]);
			}
		}

		return query;
	}

	public int executeUpdate(final String hql, final Object... values)
	{

		return createQuery(hql, values).executeUpdate();
	}

	public int executeUpdate(final String hql, final Map<String, Object> values)
	{
		return createQuery(hql, values).executeUpdate();
	}

	public void initEntity(T entity)
	{
		Hibernate.initialize(entity);
	}

	public void initEntity(List<T> entityList)
	{
		for (T entity : entityList)
		{
			Hibernate.initialize(entity);
		}
	}

	/**
	 * 
	 * Description : 根据Criterion条件创建Criteria
	 * 
	 * @param criterions
	 * @return
	 * 
	 */
	public Criteria createCriteria(final Criterion... criterions)
	{
		Criteria criteria = getSession().createCriteria(entityClass);
		for (Criterion c : criterions)
		{
			criteria.add(c);
		}
		return criteria;
	}

}
